<?php

namespace App\Repositories;

use App\Http\Services\SendSmsService;
use App\Models\ComboSpecItem;
use App\Models\DailyMenu;
use App\Models\LouAddress;
use App\Models\Member;
use App\Models\MemberAddress;
use App\Models\Order;
use App\Models\OrderAddress;
use App\Models\OrderAutoAccept;
use App\Models\OrderComboProduct;
use App\Models\OrderDeliver;
use App\Models\OrderLog;
use App\Models\OrderProduct;
use App\Models\OrderResult;
use App\Models\OrderSku;
use App\Models\Printer;
use App\Models\PrinterTask;
use App\Models\PrinterTaskOrder;
use App\Models\Product;
use App\Models\SmsLog;
use App\Models\Supplier;
use App\Models\Wemch;
use App\Repositories\Api\DailyMenuRepository;
use Cache;
use Exception;
use Illuminate\Support\Facades\Log;

class OrderRepository
{

    public function getById($id = '')
    {
        return Order::query()->where("id", "=", $id)->first();
    }

    public function getShopIdById($id = 0)
    {
        return Order::query()->where("id", "=", $id)->value("shop_id");
    }

    public function getByOutTradeNo($out_trade_no, $is_order = false)
    {
        if ($is_order) {
            $res = $this->getById($out_trade_no);
        } else {
            $res = Order::query()->where("out_trade_no", "=", $out_trade_no)->first();
        }
        if (empty($res))
            return null;

        $res['address'] = $this->getAddressById($res['id']);
        $res['products'] = $this->getOrderProductsById($res['id']);

        if (!empty($res['shop_id'])) {
            $shop = Supplier::query()->where(['id' => $res['shop_id']])->first(['id', 'status', 'open_printer_task', 'is_remark', 'delivery_phone', 'type', 'title', 'banner', 'contact_phone', 'bag_price', 'shipping_fee']);
            $shop['min_money'] = formatNum($shop['min_money']);
            $res['shop'] = $shop;
        }
        $res = $this->_rich($res);

        if ($res['status'] == 1) {
            $res['end_time'] = date("Y-m-d H:i:s", strtotime("+10 minutes", strtotime($res['create_time'])));
        }

        return $res;
    }

    private function _rich($res)
    {
        if (empty($res))
            return $res;

        //收货状态
        $res['receipt_status_title'] = Order::receiptStatus($res['receipt_status']);
        //发货状态
        $res['delivery_status_title'] = Order::deliveryStatus($res['delivery_status']);
        //配送状态
        $res['deliver_status_title'] = Order::deliverStatus($res['deliver_status']);

        //获取菜单
        if ($res['menu_id']) {
//            $menu = (new DailyMenuRepository())->getOne($res['menu_id']);
            $res['menu_title'] = $res['delivery_date'] . ' ' . menu_type($res['menu_type']);
//            $res['menu_title'] = $menu['title'] ?? "";
//            $res['menu_end_time'] = $menu['end_time'] ?? '';
            $res['menu_end_time'] = substr($res['mealtime'], 0, 16) ?? '';
        }

        $res['bag_price'] = formatNum($res['bag_price']);
        $res['express_price'] = formatNum($res['express_price']);
        $res['coupon_price'] = formatNum($res['coupon_price']);
        if ($res['deliver_time'])
            $res['deliver_time'] = date("Y-m-d H:i", $res['deliver_time']);

        // 送达时间
        if ($res['shop_type'] == 0) {
            $res['delivery_date'] = $res['delivery_date'] . ' ' . substr($res['delivery_start_time'], 0, 5) . '-' . substr($res['delivery_end_time'], 0, 5);
        }

        $res = $this->getCurrentStatus($res);

        return $res;
    }

    // 获取订单支付金额
    public function getTotalPriceById($order_id = 0)
    {
        if (!$order_id) return "";
        return Order::where("id", "=", $order_id)->value("total_price");
    }

    /**
     * 删除
     * @Author   thomashtao               bosslen
     * @DateTime 2021-11-08T22:42:14+0800
     * @param string $order_id [description]
     */
    public function deleteOrder($order_id = "")
    {
        $order = Order::where("order_id", "=", $order_id)->first();
        if (!$order)
            throw new Exception("订单不存在");

        if ($order['created_uid'] != UID)
            throw new Exception("无权限");

        Order::where("id", "=", $order['id'])->update(['is_del' => 1]);

        return true;
    }

    /**
     * 修改金额
     * @Author   thomashtao               bosslen
     * @DateTime 2021-11-08T22:56:15+0800
     * @param    [type]                   $order_id [description]
     * @param    [type]                   $price    [description]
     */
    public function updatePrice($id, $price)
    {
        $order = Order::where("id", "=", $id)->find();

        if ($order['created_uid'] != UID)
            throw new Exception("无权限");

        if ($order['paid'])
            throw new Exception("订单已支付，不可修改");

        $res = Order::where("id", "=", $order['id'])->update(['total_price' => $price]);

        return $res;
    }

    public function updateOrder($trade_no = "", $out_trade_no = "", $is_order = false, $pay_data = [])
    {
        if (!$out_trade_no) return;
        if ($is_order) {
            $order = $this->getById($out_trade_no);
        } else {
            $order = $this->getByOutTradeNo($out_trade_no);
        }

        $order = $order->toArray();
        if (empty($order) || intval($order['status']) != 1)
            return false;

        $data['status'] = 10;
        $data['transaction_id'] = $trade_no;
        $data['pay_time'] = time();
        $data['mch_id'] = empty($pay_data['mch_id']) ? '' : $pay_data['mch_id'];
//        file_put_contents("/tmp/check_qrcode_ablumn.txt", "pay_data: " . var_export($pay_data, true) . "\n", 8);

        //当前菜单编号
        if (!empty($order['menu_id'])) { //根据日期来计算单号
            //判断今天有没有记录
            $day_cache_key = "menuDay_" . $order['menu_id'] . date("Ymd");
            if (getRedisByKey($day_cache_key)) {
                $amount = Order::query()
                    ->where(['menu_id' => $order['menu_id']])
                    ->whereIn("status", [10, 20, 60])
                    ->whereBetween("create_time", [strtotime(date("Y-m-d")), strtotime(date("Y-m-d", strtotime("+1 day")))])
                    ->count("id");
            } else {
                $amount = 0;
                setRedisByDb($day_cache_key, 1, 24 * 3600);
            }
            $data['callNo'] = $this->_create_callno($amount + 1);
        }

        //$data['platform'] = "weapp";
        Order::query()->where("id", "=", $order['id'])->update($data);

        //增加会员积分
        Member::query()->where("id", $order['uid'])->increment("integral", intval($order['total_price']));
//        file_put_contents("/tmp/check_qrcode_ablumn.txt", $order['id'] . "2" . "\n", 8);

        //增加订单结果集
        OrderResult::create([
            'uid' => $order['uid'],
            'price' => $order['total_price'],
            'order_id' => $order['id'],
            'fact_price' => round($pay_data['total_fee'] / 100, 2),
            'pay_data' => serialize($pay_data),
            'status' => (round($pay_data['total_fee'] / 100, 2) == $order['total_price'] ? 1 : 0)
        ]);

//        file_put_contents("/tmp/check_qrcode_ablumn.txt", $order['id'] . "3" . "\n", 8);
        //下单减库存
        $shop = Supplier::query()->where("id", $order['shop_id'])->first(['id', 'stock_cal_type', 'accept_order_type']);
        if (intval($shop['stock_cal_type']) == 1) {
            $orderProducts = OrderProduct::query()->where(['order_id' => $order['id']])->get(['id', 'product_id', 'amount'])->toArray();

            foreach ($orderProducts as $product) {
                Product::query()->where("id", $product['product_id'])->decrement("stock", intval($product['amount']));
            }
        }

//        if(UID == )

        file_put_contents("/tmp/check_qrcode_ablumn.txt", $order['id'] . "4" . "\n", 8);

        //接单类型
        if (intval($shop['accept_order_type'] ?? 0) == 1) {
            OrderAutoAccept::create([
                'order_id' => $order['id'],
                'shop_id' => $order['shop_id'] ?? 0,
            ]);
        }

        return true;
    }

    /**
     * 自动接单
     */
    public function autoAcceptOrders()
    {
        $orderList = Order::from("order as o")
            ->join("order_auto_accept as  oa", "oa.order_id", "=", "o.id")
            ->where(['oa.status' => 0])
            ->where("oa.create_time", "<=", date("Y-m-d H:i:s", strtotime("-3 minutes")))
            ->get(['oa.id', 'o.id as order_id', 'o.status as order_status', 'o.delivery_status'])
            ->toArray();

        if (empty($orderList))
            return true;

        foreach ($orderList as $k => $v) {
            $cache_key = "orderAcceptId" . $v['id'];

            //判断是否存在
            if (getRedisByKey($cache_key) == $v['id'] || OrderAutoAccept::query()->where(['id' => $v['id']])->value("status") == 1)
                continue;

            setRedisByDb($cache_key, 60);
//            Cache::set($cache_key, 1, 60);
            if ($v['order_status'] != 10) {
                OrderAutoAccept::query()->where("id", $v['id'])->update(['status' => 1]);
                continue;
            }

            if (OrderLog::where(['order_id' => $v['order_id'], 'create_user_id' => -1, 'status' => 1])->count("id"))
                continue;

            file_put_contents("/tmp/order_auto.log", var_export($v['id'] . '-' . date("Y/m/d H:i:s"), true) . "\n", 8);
            $shopId = Order::query()->where(['id' => $v['order_id']])->value("shop_id");
            if (empty($shopId))
                continue;

            // 接单
            $printerId = Printer::query()->where(["shop_id" => $shopId, 'type' => 1, 'status' => 1])->orderBy("id", "desc")->value("id");
            if (!empty($printerId)) {
                $this->printerOrder([
                    'orderId' => $v['order_id'],
                    'printer_id' => $printerId
                ], $printerId, 2);
            }

            //品单打印机
            $printerLabelId = Printer::query()->where(["shop_id" => $shopId, 'type' => 2, 'status' => 1])->orderBy("id", "desc")->value("id");
            if ($printerLabelId) {
                (new PrinterRepository())->printerLabel(['orderId' => $v['order_id']], $printerLabelId, 2);
            }
            Order::query()->where("id", $v['order_id'])->update(['delivery_status' => 10]);
            //自动接单
            OrderAutoAccept::query()->where("id", $v['id'])->update(['status' => 1]);

            //增加日志
            OrderLog::insert([
                'order_id' => $v['order_id'],
                'create_user_id' => -1,
                'create_time' => date("Y-m-d H:i:s"),
                'update_time' => date("Y-m-d H:i:s"),
                'status' => 1,
                'is_auto' => 1,
                'original' => 1
            ]);
        }
    }

    /**
     * 生成桌号
     * @Author   thomashtao               bosslen
     * @DateTime 2024-02-28T11:57:32+0800
     * @param integer $no [description]
     * @return   [type]                           [description]
     */
    private function _create_callno($no = 1)
    {
        $num = "";

        for ($i = 0; $i < (4 - strlen($no)); $i++) {
            $num .= '0';
        }

        return $num . $no;
    }

    public function generateOrder($data)
    {
        if (!$data) return null;

        $data['uid'] = request()->get("wechat_admin_id");
        if (!$data['pay_type']) {
            $data['pay_type'] = 20;
        }

        if (!$data['out_trade_no']) {
            $data['out_trade_no'] = date('ymdHis') . GenSecret(6, 1);
        }

        if ($data['status'] == 10) {
            /*
            $start = Carbon::now()->startOfDay();
             $end = Carbon::now()->endOfDay();
            */
            //当前菜单编号
            $amount = Order::query()
                ->where(['menu_id' => $data['menu_id']])
                ->whereIn("status", [10, 20, 60])
                //筛选今天的数据
                ->whereBetween("create_time", [strtotime(date("Y-m-d")), strtotime(date("Y-m-d", strtotime("+1 day")))])
                ->count("id");

            $data['callNo'] = $this->_create_callno($amount + 1);
        }

        $goodsList = $data['goodsList'] ?? [];
        unset($data['goodsList']);

        $res = Order::create($data);
        if (!empty($res)) {

            foreach ($goodsList as $k => &$goods) {
                $goods['order_id'] = $res['id'];
                $skus = $goods['skus'] ?? null;
                if (!empty($skus)) {
                    unset($goods['skus']);
                }
                $order_product_id = OrderProduct::create($goods)->id;

                if (empty($skus)) continue;
                foreach ($skus as $sk => &$sv) { //增加规格
                    $sv['order_id'] = $res['id'];
                    $sv['order_product_id'] = $order_product_id;
                }
                OrderSku::insert($skus);
            }
        }

        return $res;
    }

    public function getLists($filter, $pageNum = 1, $pageSize = 20, $just_amount = false, $field = false)
    {
        !$field && $field = "id,type,shop_id,mealtime,menu_type,shop_type,out_trade_no,uid,total_price,amount,status,coupon_price,express_price,deliver_status,delivery_status,receipt_status,create_time,menu_id,order_source,delivery_date,delivery_start_time,delivery_end_time";
        $res = Order::query()
            ->where("uid", "=", intval($filter['uid']))
            ->when(isset($filter['status']), function ($q) use ($filter) {
                if (is_array($filter['status'])) {
                    return $q->whereIn("status", $filter['status']);
                } else {
                    return $q->where("status", "=", intval($filter['status']));
                }
            })
            ->when(strlen($filter['delivery_status']), function ($q) use ($filter) {
                return $q->where("delivery_status", intval($filter['delivery_status']));
            })
            ->when(strlen($filter['deliver_status']), function ($q) use ($filter) {
                return $q->where("deliver_status", intval($filter['deliver_status']));
            })
//            ->where("id", "<", 14100)
            ->where(['is_delete' => 2])
            ->orderBy("id", "desc")
            ->paginate($pageSize, array_filter(explode(",", $field)), null, $pageNum)
            ->toArray();

        $res = filterPaginateData($res);
        foreach ($res['items'] as $k => &$v) {
            $v = $this->getCurrentStatus($v);
            $v['total_price'] = $v['total_price'] == intval($v['total_price']) ? intval($v['total_price']) : $v['total_price'];
            $v['products'] = $this->getOrderProductsById($v['id']);

            if (isset($v['shop_id'])) {
                $v['shop'] = Supplier::query()->where(['id' => $v['shop_id']])->first([
                    'id', 'type', 'title', 'banner', 'thumb', 'min_money', 'contact_phone', 'delivery_phone', 'status'
                ]);

                $v['shop']['min_money'] = formatNum($v['shop']['min_money']);
                $v['bag_price'] = formatNum($v['bag_price']);
                $v['express_price'] = formatNum($v['express_price']);
            }

            $v['total_price'] = formatNum($v['total_price']);
            /*$menu = (new DailyMenuRepository())->getOne($v['menu_id']);
            if ($menu) {
                $v['menu_title'] = $menu['title'] ?? "";
                $v['menu_end_time'] = substr($menu['deliver_time'], 0, 16) ?? '';
            }
            */
            if ($v['menu_id']) {
                $v['menu_title'] = $v['delivery_date'] . menu_type($v['menu_type']);
                $v['menu_end_time'] = substr($v['mealtime'], 0, 16) ?? '';
            }

            // 送达时间
            if ($v['shop_type'] == 0) {
                $v['delivery_date'] = $v['delivery_date'] . ' ' . substr($v['delivery_start_time'], 0, 5) . '-' . substr($v['delivery_end_time'], 0, 5);
            }
            if ($v['status'] == 1) {
                $v['end_time'] = date("Y-m-d H:i:s", strtotime("+10 minutes", strtotime($v['create_time'])));
            }
        }

        return $res;
    }

    //增加地址
    public function addOrderAddress($order_id = null, $address_id = null)
    {
        $order_address_id = OrderAddress::where("id", $order_id)->value("id");
        $address = MemberAddress::query()->where("id", $address_id)->first()->toArray();
        if (empty($address))
            return false;

        $data['order_id'] = $order_id;
        $data['city_id'] = $address['city_id'];
        $data['region_id'] = $address['region_id'];
        $data['province_id'] = $address['province_id'];
        $data['district'] = $address['district'];
        $data['address'] = $address['address'];
        $data['consignee'] = $address['consignee'];
        $data['phone'] = $address['phone'];
        $data['uid'] = UID;
        $data['update_time'] = $data['update_time'] = time();

        if ($order_address_id) {
            OrderAddress::query()->where("id", $order_address_id)->update($data);
        } else {
            OrderAddress::create($data);
        }

        return true;
    }

    //订单地址
    public function getAddressById($order_id = null)
    {
        if (empty($order_id))
            return null;

        $redis_key = "memberOrderAddress_" . $order_id;
        $res = getRedisByKey($redis_key);
        if (!empty($res))
            return $res;

        $res = OrderAddress::query()->where("order_id", $order_id)->first();
        if (empty($res))
            return null;

        $res['province'] = LouAddress::query()->where(['id' => $res['province_id']])->value("title");
        is_numeric($res['province']) && $res['province'] .= '号楼';
        $res['city'] = LouAddress::query()->where(['id' => $res['city_id']])->value("title");
        is_numeric($res['city']) && $res['city'] .= 'F';
        $res['region'] = LouAddress::query()->where(['id' => $res['region_id']])->value("title");

        if (!empty($res['district'])) {
            $res['district_title'] = LouAddress::query()->where(['id' => $res['district']])->value("title");
            is_numeric($res['district_title']) && $res['district_title'] .= '床';
        }

        setRedisByDb($redis_key, $res);
        return $res;
    }

//    订单产品
    public function getOrderProductsById($order_id = null)
    {
        if (empty($order_id))
            return null;

        $redis_key = "memberOrderProductList_" . $order_id;
        $goodsList = getRedisByKey($redis_key);

        if (!empty($goodsList))
            return $goodsList;

        $goodsList = OrderProduct::query()->where(['order_id' => $order_id])->orderBy("id", "asc")->get([
            'id', 'type', 'order_id', 'product_id', 'product_price', 'product_price as price', 'product_title as title', 'thumb', 'stall_id', 'amount'
        ])->toArray();

        foreach ($goodsList as $k => &$v) {
            $goodsList[$k]['product_price'] = formatNum($v['product_price'] ?? 0);
            $goodsList[$k]['price'] = formatNum($v['price'] ?? 0);

            if ($v['type'] == 2) {//多规格
                $v['skus'] = OrderSku::query()->where([
                    'order_product_id' => $v['id']
                ])->orderBy("id", "asc")
                    ->get(['id', 'spec_item_id', 'spec_item_title', 'spec_price'])
                    ->toArray();

                if ($v['skus']) {
                    $v['skuTxt'] = implode("、", get_column($v['skus'], "spec_item_title"));

                    foreach ($v['skus'] as $sk => &$sv) {
                        $sv['spec_price'] = formatNum($sv['spec_price']);
                    }
                }

            } else if ($v['type'] == 1) { //套餐
                $v['skus'] = OrderSku::query()->where([
                    'order_product_id' => $v['id']
                ])->orderBy("id", "asc")
                    ->get(['id', 'goods_id', 'spec_id', 'spec_item_id', 'spec_item_title', 'sequence', 'amount'])
                    ->toArray();
                if ($v['skus']) {
                    $skuTxt = [];
                    foreach ($v['skus'] as $sk => $sv) {
                        $skuTxt[] = $sv['spec_item_title'] . 'x' . $sv['amount'];
                    }
                    $v['skuTxt'] = implode("、", $skuTxt);
                }
            }
        }

        setRedisByDb($redis_key, $goodsList ?? null);
        return $goodsList;
    }

    /**
     * 通过产品编号获取订单产品
     * @param $order_product_id
     */
    public function getOrderSkusByOpid($order_product_id = 0, $product_type = 0)
    {
        if (!intval($order_product_id) || !$product_type || !in_array($product_type, [1, 2]))
            return null;

        $redis_key = "orderProductSkus_" . $order_product_id . "_" . $product_type;
        $res = getRedisByKey($redis_key, 2);
        if (!empty($res))
            return $res;

        $model = OrderSku::from("order_sku as os")
            ->where("os.order_product_id", $order_product_id)
            ->orderBy("os.id", "asc");

        if ($product_type == 2) {
            $skus = $model->get(['os.id', 'os.goods_id', 'os.spec_id', 'os.spec_item_id', 'os.spec_item_title', 'os.sequence', 'os.amount'])->toArray();
            if (empty($skus))
                return null;

            $skuTxt = "规格：" . implode("、", get_column($skus, "spec_item_title"));
        } else if ($product_type == 1) {
            $skus = $model->join("combo_spec_item as cs", "cs.id", "=", "os.spec_item_id")
                ->get(['os.id', 'os.goods_id', 'os.spec_id', 'os.spec_item_id', 'os.spec_item_title', 'cs.product_id as item_product_id', 'os.sequence', 'os.amount'])
                ->toArray();

            if (empty($skus))
                return null;

            $skuTxt = [];
            foreach ($skus as $sk => $sv) {
                $skuTxt[] = $sv['spec_item_title'] . 'x' . $sv['amount'];
            }
            $skuTxt = implode("、", $skuTxt);
        } else {
            return null;
        }

        $res = [
            "skus" => $skus,
            'skuTxt' => $skuTxt
        ];
        setRedisByDb($redis_key, $res, 0, 2);
        return $res;
//        return compact("skus", "skuTxt");
    }


    /**
     * 订单-产品规格
     * @param int $order_id
     * @param int $product_id
     */
    public function getOrderSkus($order_id = 0, $product_id = 0, $product_type = 0)
    {
        if (!$product_type || !$order_id || !$product_id)
            return null;

        if ($product_type == 2) {//规格

            $skus = OrderSku::query()->where([
                'order_id' => $order_id,
                'type' => 0,
                'goods_id' => $product_id,
            ])->orderBy("id", "asc")
                ->get(['id', 'spec_item_id', 'spec_item_title', 'spec_price'])
                ->toArray();

            if ($skus) {
                $skuTxt = "规格：" . implode("、", get_column($skus, "spec_item_title"));

                foreach ($skus as $sk => &$sv) {
                    $sv['spec_price'] = formatNum($sv['spec_price']);
                }
            }

            return compact("skus", "skuTxt");
        } else if ($product_type == 1) { //套餐
            $skus = OrderSku::query()->where([
                'order_id' => $order_id,
                'goods_id' => $product_id,
                'type' => 1,
            ])->orderBy("id", "asc")
                ->get(['id', 'goods_id', 'spec_id', 'spec_item_id', 'spec_item_title', 'sequence', 'amount'])
                ->toArray();

            if ($skus) {
                $skuTxt = [];
                foreach ($skus as $sk => $sv) {
                    $skuTxt[] = $sv['spec_item_title'] . 'x' . $sv['amount'];
                }

                $skuTxt = implode("、", $skuTxt);
            }

            return compact("skus", "skuTxt");
        } else {
            return null;
        }

    }

    /**
     * 取消订单并退款
     * @param null $out_trade_no
     */
    public function cancelOrder($out_trade_no = null, $reason = null, $original = null)
    {
        if (empty($out_trade_no)) {
            return retFail("订单异常");
        }

        $order = Order::query()->where("out_trade_no", $out_trade_no)->first();
        if (empty($order))
            return retFail("订单不存在");

        //定时取消 ，非付款状态下
        if ($original == 'countdown' && $order['status'] != 1) {
            return retSuc([], "订单已付款成功");
        }

        if ($order['uid'] != UID)
            return retFail("无权限");

        if ($order['status'] == 1) {
            Order::query()->where(['id' => $order['id']])
                ->update([
                    'status' => 80,
                    'reason' => $reason ?? "",
                    'refund_time' => date("Y-m-d H:i:s")
                ]);

            //取消订单
            $this->addLog([$order['id']], 80, UID, 2);

            return retSuc([], "取消成功");
        }

        if ($order['status'] != 10) {
            return retFail("订单不可取消");
        }
        if ($order['delivery_status'] > 0) {
            return retFail("订单已制作，不可取消");
        }

        //取消日志
        Log::channel("ordercancel")->info(json_encode([
            'out_trade_no' => $order['out_trade_no'],
            'status' => $order['status'],
            'deliver_status' => $order['deliver_status'],
            'delivery_status' => $order['delivery_status'],
            'active_uid' => UID,
            'action_time' => date("Y-m-d H:i:s")
        ]));

        // 代下单  只取消  不退款
        if ($order['order_source'] == 1) {
            Order::query()->where(['id' => $order['id']])
                ->update([
                    'status' => 80,
                    'reason' => $reason ?? "",
                    'refund_time' => date("Y-m-d H:i:s")
                ]);


            //取消订单
            $this->addLog([$order['id']], 80, UID, 2);
            return retSuc([], "取消成功");
        }

        //判断是否要退款  是否在指定时间内取消订单
        $refund_data['transaction_id'] = $order['transaction_id'];
        $refund_data['total_fee'] = $order['total_price'];
        $refund_data['refund_fee'] = $order['total_price'];
        $refund_data['refund_no'] = $order['type'] . 'refund' . date('Ymdhis') . rand(1000, 9999);

        $config = null;
        if (!empty($order['mch_id'])) { //其他商户
//            , 'status' => 1
            $wemch = Wemch::query()->where(['shop_id' => $order['shop_id'], 'mch_id' => $order['mch_id']])->first();
            if ($wemch) {
                $config = [
                    'mch_id' => trim($wemch['mch_id']),
                    'mch_secret' => trim($wemch['secret']),
                    'cert_path' => request()->server('DOCUMENT_ROOT') . $wemch['cert_path'],
                    'key_path' => request()->server('DOCUMENT_ROOT') . $wemch['key_path'],
                ];
            }
        }
        try {
            $result = (new WechatRepository($config ?? null))->refund($refund_data);
            /*if ($result['return_code'] == 'FAIL') {
                return retFail($result['return_msg']);
            }*/
        } catch (Exception $e) {
            return retFail($e->getMessage());
        }

        $order_data = [];
        if ($result["return_code"] == 'SUCCESS' && $result["result_code"] == 'SUCCESS') {
            $order_data["refund_status"] = 1;
            $order_data['refund_id'] = $result["refund_id"];
            $order_data['refund_sn'] = $refund_data['refund_no'];
            $order_data['refund_price'] = $refund_data['refund_fee'];
            $order_data['refund_time'] = date("Y-m-d H:i:s");
            $order_data['status'] = 60;
            $order_data['reason'] = $reason ?? "";
            Order::query()->where("id", $order['id'])->update($order_data);

            //取消订单
            $this->addLog([$order['id']], 60, UID, 2);

            //减少会员积分
            Member::query()->where("id", $order['uid'])->decrement("integral", intval($order['total_price']));

            return retSuc([], "退款成功，费用将原路退回");
        } else {
            $order_data["refund_status"] = 2;
            $order_data['reason'] = $reason ?? "";
            $order_data["refund_error_message"] = trim($result["err_code_des"]);

            if ($order_data['refund_error_message'] == "订单已全额退款") {
                Order::query()->where("id", $order['id'])->update(['status' => 60]);
                return retSuc([], "已成功取消，请不要重复操作！");
            }
            return retFail(trim($result["err_code_des"]));
        }
    }

    //确认配送
    public function confirmDeliver($filter)
    {
        $orderIds = $this->_get_list($filter, "o.id", 1);
        if (empty($orderIds)) {
            return retSuc(['suc' => 0]);
        }
        $deliverStatsList = [
            17 => 4,//成功
            16 => 3,//待分拣
            12 => 2,//正在配送
        ];
        $deliver_status = $deliverStatsList[$filter['status']];

        $o_data['deliver_status'] = $deliver_status;
        if ($filter['status'] == 17) { //出餐中
            $o_data['status'] = 20;
            $o_data['confirm_time'] = time();
        } else if ($filter['status'] == 16) {
            $o_data['pick_time'] = time();
        } else {
            $o_data['deliver_time'] = time(); //出餐时间
            $o_data['delivery_status'] = 20;
        }
        Order::whereIn("id", $orderIds)->update($o_data);

        foreach ($orderIds as $k => $orderId) {
            $deliver = OrderDeliver::query()->where(['order_id' => $orderId, 'deliver_uid' => $filter['uid']])->whereIn("status", [10, 30])->first();
            if ($deliver) {
                if ($filter['status'] == 17) {
                    OrderDeliver::query()->where("id", $deliver['id'])->update(['deliver_status' => 4, 'status' => 30]);
                    continue;
                } else {
                    continue;
                }
            }

            OrderDeliver::create([
                'deliver_source' => 30,
                'order_id' => $orderId,
                'deliver_uid' => $filter['uid'],
                'deliver_status' => $deliver_status,
                'status' => $filter['status'] == 12 ? 30 : 10,
                'shop_supplier_id' => intval($filter['shop_id'])
            ]);
        }

        //增加日志
        $this->addLog($orderIds, $deliver_status, UID, 1);

        return retSuc(['suc' => count($orderIds)]);
    }

    /**
     * 配送数据
     * @param $filter
     * @param $pageNum
     * @param $pageSize
     */
    public function getOrderDliverList($filter, $pageNum, $pageSize)
    {
        $filter['pageSize'] = $pageSize;
        $filter['pageNum'] = $pageNum;

        $res = $this->_get_list($filter, null, 2);
        $res = filterPaginateData($res);

        foreach ($res['items'] as $k => &$v) {
            $v = $this->getCurrentStatus($v);
            $v['products'] = $this->getOrderProductsById($v['id']);

            $v['province'] = LouAddress::query()->where(['id' => $v['province_id']])->value("title");
            is_numeric($v['province']) && $v['province'] .= '号楼';
            $v['city'] = LouAddress::query()->where(['id' => $v['city_id']])->value("title");
            is_numeric($v['city']) && $v['city'] .= 'F';
            $v['region'] = LouAddress::query()->where(['id' => $v['region_id']])->value("title");

            if (!empty($v['district'])) {
                $v['district_title'] = LouAddress::query()->where(['id' => $v['district']])->value("title");
                is_numeric($v['district_title']) && $v['district_title'] .= '床';
            }

            $v['menu_title'] = date("Y年m月d日", strtotime($v['menu_date'])) . ' ' . menu_type($v['menu_type']);
            $v['menu_end_time'] = substr($v['mealtime'], 0, 16);

            $v['delivery_date'] = $v['delivery_date'] . ' ' . substr($v['delivery_start_time'], 0, 5) . '-' . substr($v['delivery_end_time'], 0, 5);

        }

        return $res;
    }

    /**
     * 配送统计
     */
    public function getOrderDliverStat($filter)
    {
        $res = $this->_get_list($filter, null);
        if (empty($res))
            return [];

        $data = [];
        $replace_amount = 0;

        foreach ($res as $k => $order) {
            if ($filter['shop_type'] == 1) {
                $data[$order['province_id']][$order['city_id']][] = $order;
            } else {
                $data[$order['province_id']][$order['city_id']][$order['shop_id']][] = $order;
            }
            if ($order['order_source'] == 1) {
                $replace_amount += 1;
            }
        }

        $statList = [];
        $product_amount = 0;

        foreach ($data as $k => $v) { //省
            $province = LouAddress::query()->where("id", $k)->value("title");
            $d['province'] = is_numeric($province) ? ($province . '号楼') : $province;

            foreach ($v as $k1 => $v1) { //市
                $city = LouAddress::query()->where("id", $k1)->value("title");
                $d['city'] = is_numeric($city) ? ($city . 'F') : $city;
                $d['city_id'] = $k1;

                $d['product_amount'] = OrderProduct::query()->whereIn("order_id", get_column($v1, "id"))->sum("amount");
                if ($filter['shop_type'] == 1) {//食堂
                    $d['order_amount'] = count($v1);
//                    $d['product_amount'] = array_sum(get_column($products, "amount"));
                    $product_amount += $d['product_amount'];
                } else {//单店
                    foreach ($v1 as $k2 => $v2) {  //店铺
                        $d['order_amount'] = count($v2);
                        $d['shop_title'] = $v2[0]['shop_title'];
//                        $products = $this->_stat_order_product(get_column($v2, "id"));
//                        $d['product_amount'] = array_sum(get_column($products, "amount"));
                        $product_amount += $d['product_amount'];
                    }
                }
                $statList[] = $d;
            }
        }

        return [
            'statList' => $statList,
            'total' => count($statList),
            'order_amount' => count($res),
            'product_total' => $product_amount,
            'replace_amount' => $replace_amount
        ];
    }

    /**
     * 获取订单对应的产品统计
     * @param null $orderIds
     * @return void|null
     */
    function _stat_order_product($orderIds = null)
    {
        if (empty($orderIds))
            return null;

        $orderProducts = OrderProduct::query()->whereIn("order_id", $orderIds)->get([
            'id', 'product_id', 'amount', 'type', 'product_title as title'
        ]);

        if (empty($orderProducts))
            return null;

        $orderProducts = $orderProducts->toArray();
        foreach ($orderProducts as $k => &$v) {
            if (intval($v['type']) == 0) continue;

            $v['sub'] = OrderComboProduct::query()
                ->where(['order_product_id' => $v['id']])
                ->orderBy('sequence', 'asc')
                ->get(['title', 'price', 'sequence', 'amount']);

            if (!empty($v['sub'])) {
                $v['sub'] = $v['sub']->toArray();
            }
        }

        return $orderProducts;
    }

    /**
     * @param $filter
     * @param null $field
     * @param $type true  1:返回单个字段 2:返回分页原型
     * @return array
     */
    private function _get_list($filter, $field = null, $type = 0)
    {

        if (empty($field)) {
            $field = ["o.*", 's.title as shop_title', 's.contact_phone as shop_mobile', 'p.province_id', 'p.city_id', 'p.region_id', 'p.phone', 'p.consignee', 'p.district', 'p.address', 'd.type as menu_type', 'd.date as menu_date', 'd.end_time as menu_end_time'];
        }

        $_whereRaw = [];
        if (!empty($filter['start_time'])) {
            $_whereRaw[] = 'wx_o.create_time >= ' . strtotime($filter['start_time']);
        }

        if (!empty($filter['end_time'])) {
            $_whereRaw[] = 'wx_o.create_time < ' . strtotime($filter['end_time']);
        }

//        判断是否有统计城市
        if (!empty($filter['stat_city_ids'])) {
            $city_ids = array_filter(explode("-", $filter['stat_city_ids']));
        } else {
            $city_ids = $filter['city_id'] ?? [];
            if (!empty($filter['provinceIds'])) {
                if (!is_array($filter['provinceIds'])) {
                    $filter['provinceIds'] = json_decode($filter['provinceIds']);
                }
                if (!empty($filter['provinceIds'])) {
                    $cityIds = LouAddress::query()->whereIn("pid", $filter['provinceIds'])->pluck("id")->toArray();
                    $city_ids = array_unique(array_merge($city_ids, $cityIds));
                }
            }
        }

        if ($filter['deliver_time']) { //配送时间格式化
            $deliver_time = deliver_timeList($filter['deliver_time']);

            if ($deliver_time) {
                $deliver_time = array_filter(explode("-", $deliver_time));
            }
            $filter['deliver_time'] = $deliver_time;
        }

        $model = Order::from("order as o")
            ->join("order_address as p", "p.order_id", "=", "o.id")
            ->join("daily_menu as d", "d.id", "=", "o.menu_id")
            ->join("supplier as s", "s.id", "=", "o.shop_id")
            ->when(!empty($_whereRaw), function ($q) use ($_whereRaw) {
                return $q->whereRaw(" ( " . implode(" and ", $_whereRaw) . " ) ");
            })
            ->when(!empty($filter['shop_id']), function ($q) use ($filter) {
                if (is_array($filter['shop_id'])) {
                    return $q->whereIn("o.shop_id", $filter['shop_id']);
                } else {
                    return $q->where("o.shop_id", intval($filter['shop_id']));
                }
            });

        if ($filter['shop_type'] == 1) { //食堂
            $model->where("shop_type", 1)->when(!empty($filter['menu_date']), function ($q) use ($filter) {
                return $q->where("d.date", $filter['menu_date']);
            })->when(!empty($filter['menu_id']), function ($q) use ($filter) {
                if (is_array($filter['menu_id'])) {
                    return $q->whereIn("menu_id", $filter['menu_id']);
                } else {
                    return $q->where("menu_id", intval($filter['menu_id']));
                }
            });
        } else {
            $model->where(['shop_type' => 0])->where('delivery_date', $filter['current_date']);
            if ($filter['deliver_time']) {
                $model->where('delivery_start_time', '>=', $filter['deliver_time'][0] . ':00')
                    ->where('delivery_end_time', '<=', $filter['deliver_time'][1] . ':00');

            }
        }
        $model->when(!empty($filter['deliver_status']), function ($q) use ($filter) {
            if (is_array($filter['deliver_status'])) {
                return $q->whereIn("deliver_status", $filter['deliver_status']);
            } else {
                return $q->where("deliver_status", $filter['deliver_status']);
            }
        })
            ->when(!empty($city_ids), function ($q) use ($city_ids) {
                if (is_array($city_ids)) {
                    $q->whereIn("p.city_id", $city_ids);
                }
            })
            ->when(!empty($filter['ids']), function ($q) use ($filter) {
                if (is_array($filter['ids'])) {
                    $q->whereIn("o.id", $filter['ids']);
                } else {
                    $filter["ids"] = json_decode($filter['ids']);
                    $q->whereIn("o.id", $filter['ids']);
                }
            })
            ->when(!empty($filter['status']), function ($q) use ($filter) {
                if ($filter['status'] > 0) {
                    $statusMapping = $this->getStatMapping($filter['status']);

//                    dd($statusMapping);
                    foreach ($statusMapping as $sk => $sv) {
                        $q->where("o." . $sk, $sv);
                    }
                }
            })
            ->where(['o.is_delete' => 2])
//            ->orderBy("p.province_id", "asc")
//            ->orderBy("p.city_id", "asc")
            ->orderBy("o.deliver_time", "asc")
            ->orderBy("o.delivery_date", "asc")
            ->orderBy("o.delivery_start_time", "asc")
            ->orderBy("o.create_time", "desc");

        if ($type == 1) {
            return $model->pluck($field)->toArray();
        } else if ($type == 2) {
            return $model->paginate($filter['pageSize'], $field ?? "o.*", null, $filter['pageNum'])
                ->toArray();
        } else if ($type == 3) {
            return $model;
        }

        return $model->get($field)->toArray();
    }

    /**
     * 取消未支付的订单
     * 食堂类型
     */
    public function autoCancelOrder()
    {
        $orderIds = Order::from("order as o")
            ->join("daily_menu as dm", "dm.id", "=", "o.menu_id")
            ->where("o.status", 1)
            ->where(["o.shop_type" => 1])
//            ->where("UNIX_TIMESTAMP(dm.end_time) as end_time", "<", )
            ->where("dm.end_time", "<=", date("Y-m-d H:i:s"))
            ->orderBy("o.menu_id", "desc")
            ->pluck("o.id")
            ->toArray();

        if (count($orderIds) > 0) {
            //取消日志
            Log::channel("ordercancel")->info(json_encode([
                'action' => "系统取消",
                'orderIds' => $orderIds
            ]));
            Order::whereIn("id", $orderIds)->update(['status' => 80]);
            return true;
        }

        $orderIds = Order::query()
            ->where(["shop_type" => 0, "status" => 1])
            ->where("create_time", "<=", date("Y-m-d H:i:s", strtotime("-10 minutes")))
            ->pluck("id")
            ->toArray();

        if (count($orderIds) > 0) {
            //取消日志
            Log::channel("ordercancel")->info(json_encode([
                'action' => "系统取消",
                'orderIds' => $orderIds
            ]));

            Order::whereIn("id", $orderIds)->update(['status' => 80]);
            return true;
        }
    }

    /**
     * 店铺端
     * @param $filter
     * @param $pageNum
     * @param $pageSize
     */
    public function getShopOrderList($filter, $pageNum, $pageSize)
    {
        $filter['pageSize'] = $pageSize;
        $filter['pageNum'] = $pageNum;

        $res = $this->_get_list($filter, null, 2);

//        dd($filter);
        $res = filterPaginateData($res);
        foreach ($res['items'] as $k => &$v) {
            $v = $this->getCurrentStatus($v);

            $v['products'] = $this->getOrderProductsById($v['id']);
//            $v['address'] = $this->getAddressById($v['id']);
            $v['province'] = LouAddress::query()->where(['id' => $v['province_id']])->value("title");
            is_numeric($v['province']) && $v['province'] .= '号楼';
            $v['city'] = LouAddress::query()->where(['id' => $v['city_id']])->value("title");
            is_numeric($v['city']) && $v['city'] .= 'F';
            $v['region'] = LouAddress::query()->where(['id' => $v['region_id']])->value("title");

            if (!empty($v['district'])) {
                $v['district_title'] = LouAddress::query()->where(['id' => $v['district']])->value("title");
                is_numeric($v['district_title']) && $v['district_title'] .= '床';
            }

            $menu_end_time = DailyMenu::query()->where(['id' => $v['menu_id']])->value("deliver_time");
            if ($menu_end_time) {
                $v['menu_format_end_date'] = date("m/d", strtotime($menu_end_time)) . " (" . getWeek($menu_end_time) . ") " . date("h:i", strtotime($menu_end_time));
            }

            $v['menu_title'] = date("Y年m月d日", strtotime($v['menu_date'])) . ' ' . menu_type($v['menu_type']);
            if ($v['shop_type'] == 0) {
                $v['delivery_format_date'] = date("m/d", strtotime($v['delivery_date'])) . ' ' . " (" . getWeek($v['delivery_date']) . ") " . substr($v['delivery_start_time'], 0, 5) . '-' . substr($v['delivery_end_time'], 0, 5);
                $v['delivery_date'] = $v['delivery_date'] . ' ' . substr($v['delivery_start_time'], 0, 5) . '-' . substr($v['delivery_end_time'], 0, 5);
            }
        }

        return $res;
    }

    /**
     * 订单当前状态
     * @param null $order
     * @return array|mixed|null
     */
    public function getCurrentStatus($order = null)
    {
        if (empty($order))
            return $order;

        if ($order['status'] == 10) {
            //配送状态
            if ($order['delivery_status'] == 20) {
                switch ($order['deliver_status']) {
                    case 4:  //配送完成
                        $order['current_status'] = 20;
                        break;
                    case 3:  //配送中
                        $order['current_status'] = 17;
                        break;
                    case 2: //待配送/分拣中
                        $order['current_status'] = 16;
                        break;
                    default:
                        break;
                }
            } else if ($order['delivery_status'] == 10) {
                $order['current_status'] = 12; //出餐中
            } else {
                $order['current_status'] = 11; //待接单
            }

        } else if ($order['status'] == 61) {
            $order['current_status'] = 60;
        } else {
            $order['current_status'] = $order['status'];
        }

        return $order;
    }

    /**
     * 状态映射
     * @param int $status
     * @return array
     */
    public function getStatMapping(int $status = 0)
    {
        if (!$status) return [];

        $filter = [];
        switch ($status) {
            case 17://配送中
                $filter['status'] = 10;
                $filter['delivery_status'] = 20;
                $filter['deliver_status'] = 3;
                break;
            case 16: //"待分拣"  出餐中
                $filter['status'] = 10;
                $filter['delivery_status'] = 20;
                $filter['deliver_status'] = 2;
                break;
            case 12: // 待出餐
                $filter['status'] = 10;
                $filter['delivery_status'] = 10;
                break;
            case 11://待接单
                $filter['status'] = 10;
                $filter['delivery_status'] = 0;
                break;
            default:
                $filter['status'] = $status;
                break;
        }

        return $filter;
    }

    /**
     * 获取订单数据
     * @param $filter
     * @param false type  1:数量 2：返回key
     */
    public function getStat($filter, $type = 1)
    {
        $model = Order::from("order as o")
            ->join("daily_menu as dm", "dm.id", "=", "o.menu_id")
            ->when(!empty($filter['ids']), function ($query) use ($filter) {
                return $query->whereIn('o.id', $filter['ids']);
            })
            ->when(!empty($filter['menu_id']), function ($query) use ($filter) {
                if (is_array($filter['menu_id'])) {
                    return $query->whereIn('o.menu_id', $filter['menu_id']);
                } else {
                    return $query->where('o.menu_id', intval($filter['menu_id']));
                }
            })
            ->when(!empty($filter['orderIds']), function ($query) use ($filter) {
                if (is_array($filter['orderIds'])) {
                    return $query->whereIn('o.id', $filter['orderIds']);
                } else {
                    return $query->where('o.id', intval($filter['orderIds']));
                }
            })
            ->when(!empty($filter['ids']), function ($q) use ($filter) {
                if (is_array($filter['ids'])) {
                    $q->whereIn("o.id", $filter['ids']);
                } else {
                    $filter["ids"] = json_decode($filter['ids']);
                    $q->whereIn("o.id", $filter['ids']);
                }
            })
            ->when(!empty($filter['status']), function ($q) use ($filter) {
                if ($filter['status'] > 0) {
                    $statusMapping = $this->getStatMapping($filter['status']);

                    foreach ($statusMapping as $sk => $sv) {
                        $q->where("o." . $sk, $sv);
                    }
                }
            });

        if ($type == 1)
            return $model->count("o.id");
        else if ($type == 2)
            return $model->pluck("o.id")->toArray();

        return $model->get();
    }

    /**
     *管理员更新订单
     * @param
     */
    public function adminUpdateOrder($id = null, $data = null)
    {
        if (empty($id))
            return false;

        $data['update_time'] = time();
        Order::query()->when(!empty($id), function ($q) use ($id) {
            if (is_array($id)) {
                return $q->whereIn("id", $id);
            } else {
                return $q->where("id", $id);
            }
        })->update($data);

        return true;
    }

    /**
     * 档口统计
     * @param $filter
     */
    public function getOrderStallStat($filter = [])
    {
        $orderIds = $this->getOrderIdsByOrderProduct($filter);
        $fields = "op.id,op.order_id,op.type,op.amount,op.product_id,op.product_title as title,op.stall_id,o.menu_id,s.title as stall_title,m.date as menu_date,m.type as menu_type";

        if (empty($orderIds))
            return null;

        $orderProducts = OrderProduct::from("order_product as op")
            ->join("order as o", "o.id", "=", "op.order_id")
            ->join("stall as s", "s.id", "=", "op.stall_id")
            ->join("daily_menu as m", "m.id", "=", "o.menu_id")
            ->whereIn("o.id", $orderIds)
            ->orderBy("op.stall_id", "ASC")
            ->orderBy("op.product_id", "ASC")
            ->get(array_filter(explode(",", $fields)))
            ->toArray();

        if (empty($orderIds))
            return null;

        $products = [];
        foreach ($orderProducts as $k => $v) {
            if ($v['type'] != 1) {
                $products[] = $v;
                continue;
            }

            //套餐总量计算
            $skus = $this->getOrderSkus($v['order_id'], $v['product_id'], 1);
            foreach ($skus['skus'] as $sk => $sv) {
                $spec_item_goods_id = ComboSpecItem::query()->where("id", $sv['spec_item_id'])->value('product_id');
                $products[] = [
                    'order_id' => $v['order_id'],
                    'product_id' => $spec_item_goods_id,
                    'title' => $sv['spec_item_title'],
                    'amount' => intval($v['amount']) * intval($sv['amount']), //套餐 * 单品
                    'menu_id' => $v['menu_id'],
                    'stall_id' => $v['stall_id'],
                    'stall_title' => $v['stall_title'],
                    'combo_id' => $v['product_id'],
                ];
            }
        }

        $orderProducts = ass_column($products, "stall_id", true);
        $orderStat = [];

        foreach ($orderProducts as $k => $v) {//档口
            $v = ass_column($v, "menu_id", true);

            foreach ($v as $sk => $sv) { //菜单
                $sv = ass_column($sv, "product_id", true);

                foreach ($sv as $ssk => $ssv) {
                    $orderStat[] = [
                        'stall_title' => $ssv[0]['stall_title'],
                        'stall_id' => $k,
                        'order_id' => $ssv[0]['order_id'],
                        'menu_id' => $sk,
//                        'menu_title' => $ssv[0]['menu_date'] . ' ' . menu_type($ssv[0]['menu_type']),
                        'menu_title' => $ssv['menu_type'] == 1 ? menu_type($ssv[0]['menu_type']) : '普通',
                        'product_title' => $ssv[0]['title'],
                        'amount' => array_sum(get_column($ssv, "amount")),
                    ];
                }
            }
        }

        return $orderStat;
    }

    /**
     * 订单统计楼/层统计
     * 获取配送员的统计
     * @param $filter
     */
    public function getOrderStat($filter = null)
    {
        $orderIds = $this->getOrderIdsByOrderProduct($filter);

        if (empty($orderIds))
            return null;

        $addressList = OrderAddress::from("order_address as oa")
            ->join("lou_address as l", "l.id", "=", "oa.province_id")
            ->join("lou_address as la", "la.id", "=", "oa.city_id")
            ->whereIn("oa.order_id", $orderIds)
            ->orderBy("l.sort", "asc")
            ->orderBy("la.sort", "asc")
            ->get(array_filter(explode(",", "oa.*,l.title as province_title,la.title as city_title")))
            ->toarray();

        if (empty($addressList))
            return null;

        $data = [];
        foreach ($addressList as $k => $v) {
            $data[$v['province_id']][$v['city_id']][$v['region_id']][] = $v;
        }

        $statList = [];
        foreach ($data as $k => $v) { //楼
            $province_title = LouAddress::query()->where(['id' => $k])->value("title");
            foreach ($v as $s1 => $v1) { //层
                $city_title = LouAddress::query()->where(['id' => $s1])->value("title");
                $city_title = is_numeric($city_title) ? ($city_title . 'F') : $city_title;

                $d = [];
                $d['province_title'] = $province_title;
                $d['city_title'] = $city_title;

                $order_amount = 0;
                $product_amount = 0;
                foreach ($v1 as $s2 => $v2) { //科室
                    $order_amount += count($v2);
                    $products = OrderProduct::query()
                        ->whereIn("order_id", get_column($v2, "order_id"))
                        ->get(["id", "type", "product_id", "amount", "order_id"])
                        ->toArray();
                    $product_amount += array_sum(get_column($products, "amount"));
                }

                $d['product_amount'] = $product_amount;
                $d['order_amount'] = $order_amount;
                $statList[] = $d;
            }
        }

        return $statList;
    }

    /**
     * 获取档口
     * @param $filter
     */
    public function getOrderStalls($filter = null)
    {
        if (empty($filter))
            return null;

        return $this->_model_product($filter)->distinct("s.id")->get(['s.id', 's.title']);
    }

    /**
     * 获取订单编号
     * @param null $filter
     * @return array
     */
    public function getOrderIdsByFilter($filter = null)
    {
        $model = $this->_model_product($filter);
        if ($filter['shop_type'] == 0 && $filter['current_date']) {
            $model->where('o.delivery_date', $filter['current_date']);
        }
        return $model->distinct("p.order_id")
            ->orderBy("o.id", "DESC")
            ->pluck("p.order_id")
            ->toArray();
    }

    private function _model_product($filter)
    {
        if (empty($filter))
            return null;

        $model = OrderProduct::from("order_product as p")
            ->join("order as o", "o.id", "=", "p.order_id")
            ->join("stall as s", "s.id", "=", "p.stall_id");

        if ($filter['menu_type'] == 1) {  //食堂
            $model->join("daily_menu as dm", "dm.id", "=", "o.menu_id")
                ->when(!empty($filter['menu_id']), function ($q) use ($filter) {
                    if (is_array($filter['menu_id'])) {
                        return $q->whereIn("o.menu_id", $filter['menu_id']);
                    } else {
                        return $q->where("o.menu_id", $filter['menu_id']);
                    }
                });
        }

        $model->when(!empty($filter['ids']), function ($q) use ($filter) {
            if (is_array($filter['ids'])) {
                $q->whereIn("o.id", $filter['ids']);
            } else {
                $filter["ids"] = json_decode($filter['ids']);
                $q->whereIn("o.id", $filter['ids']);
            }
        })
            ->when(!empty($filter['status']), function ($q) use ($filter) {
                $statusMapping = $this->getStatMapping($filter['status']);
                foreach ($statusMapping as $sk => $sv) {
                    $q->where("o." . $sk, $sv);
                }
            })
            ->when(!empty($filter['stall_id']), function ($q) use ($filter) {
                if (is_array($filter['stall_id'])) {
                    return $q->whereIn("p.stall_id", $filter['stall_id']);
                } else {
                    return $q->where("p.stall_id", $filter['stall_id']);
                }
            })
            ->when(!empty($filter['shop_id']), function ($q) use ($filter) {
                if (is_array($filter['shop_id'])) {
                    return $q->whereIn("o.shop_id", $filter['shop_id']);
                } else {
                    return $q->where("o.shop_id", $filter['shop_id']);
                }
            })
            ->whereNull("o.deleted_at");
        return $model;
    }


    /**
     * 商家端统计
     * @param null $shop_id
     */
    public function consoleOrderStat($shop_id = null,)
    {
        if (!intval($shop_id))
            return [];

        $total_order = Order::query()->where(['shop_id' => $shop_id])
            ->whereIn("status", [10, 20])
            ->whereBetween("create_time", [
                strtotime("-1 day", strtotime(date("Y-m-d"))),
                strtotime(date("Y-m-d"))
            ])->count("id");

        $total_price = formatNum(Order::query()->where(['shop_id' => $shop_id])
            ->whereIn("status", [10, 20])
            ->whereBetween("create_time", [
                strtotime("-1 day", strtotime(date("Y-m-d"))),
                strtotime(date("Y-m-d"))
            ])->sum("total_price"));

        $ava_price = $total_order > 0 ? formatNum(round($total_price / $total_order, 2)) : 0;

        return compact("total_price", "total_order", "ava_price");
    }

    public function getConsoleShopStat($shop_id)
    {
        $yes = $this->_stat($shop_id, 1);
        $eve = $this->_stat($shop_id, 7);

        return [
            1 => $yes,
            7 => $eve,
        ];
    }

    private function _stat($shop_id = null, $day = 1)
    {
        if (!intval($shop_id))
            return [];

        $orderList = Order::query()->where(['shop_id' => $shop_id])
            ->whereIn("status", [10, 20])
            ->whereBetween("create_time", [
                strtotime("-{$day} day", strtotime(date("Y-m-d"))),
                strtotime(date("Y-m-d"))
            ])->get(['id', 'total_price', 'express_price'])->toArray();

        $amount = count($orderList);
        $total_price = formatNum(array_sum(get_column($orderList, "total_price")) - array_sum(get_column($orderList, "express_price")));
        $ava_price = $amount > 0 ? formatNum(round($total_price / $amount, 2)) : 0;

        return compact("total_price", "amount", "ava_price");
    }

    /**
     * 获取产品对应的订单
     * @param $filter
     */
    public function getOrderIdsByOrderProduct($filter = [])
    {
        $model = OrderProduct::from("order_product as p")
            ->join("order as o", "o.id", "=", "p.order_id")
            ->join("daily_menu as dm", "dm.id", "=", "o.menu_id")
            ->when(!empty($filter['menu_id']), function ($q) use ($filter) {
                if (is_array($filter['menu_id'])) {
                    return $q->whereIn("o.menu_id", $filter['menu_id']);
                } else {
                    return $q->where("o.menu_id", $filter['menu_id']);
                }
            })
            ->when(!empty($filter['status']), function ($q) use ($filter) {
                if ($filter['status'] > 0) {
                    $statusMapping = $this->getStatMapping($filter['status']);
                    foreach ($statusMapping as $sk => $sv) {
                        $q->where("o." . $sk, $sv);
                    }
                }
            })
            ->when(!empty($filter['ids']), function ($q) use ($filter) {
                if (is_array($filter['ids'])) {
                    $q->whereIn("o.id", $filter['ids']);
                } else {
                    $filter["ids"] = json_decode($filter['ids']);
                    $q->whereIn("o.id", $filter['ids']);
                }
            })
            ->when(!empty($filter['stall_id']), function ($q) use ($filter) {
                if (is_array($filter['stall_id'])) {
                    return $q->whereIn("p.stall_id", $filter['stall_id']);
                } else {
                    return $q->where("p.stall_id", $filter['stall_id']);
                }
            })
            ->when(!empty($filter['shop_id']), function ($q) use ($filter) {
                if (is_array($filter['shop_id'])) {
                    return $q->whereIn("o.shop_id", $filter['shop_id']);
                } else {
                    return $q->where("o.shop_id", $filter['shop_id']);
                }
            });

        //单店
        if ($filter['shop_type'] == 0 && $filter['current_date']) {
            $model->where("o.delivery_date", $filter['current_date']);
        }

        return $model->whereNull("o.deleted_at")
            ->distinct("p.order_id")
            ->orderBy("o.id", "DESC")
            ->pluck("p.order_id")
            ->toArray();
    }

    /**
     * 打印订单
     * @param $filter
     */
    public function printerOrder($filter, $printer_id = null, $type = 0)
    {
        if ($type == 2) { //指定订单号
            $orderIds = $filter['orderId'] ?? null;
            if (empty($orderIds))
                return retFail("请传入订单号");

            settype($orderIds, 'array');
        } else if ($type == 1) { //后台
            $orderIds = (new \App\Repositories\Manage\OrderRepository())->getOrderIdsFilter($filter);
        } else {
            $orderIds = $this->getOrderIdsByOrderProduct($filter);
        }
        if (!$orderIds)
            return retFail("无打印数据");

        //打印任务
        if (!empty($filter['shop_id']) && count($orderIds) > 1) {
            $task_data['title'] = "订单打印_" . "" . date("hi");
            $task_data['printer_sn'] = $printer_id;
            $task_data['printer_type'] = 1;
            $task_data['status'] = 0;
            $task_data['supplier_id'] = $filter['shop_id'] ?? 0;
            $task_data['amount'] = count($orderIds);
            $task_id = PrinterTask::create($task_data)->id;

            $taskOrders = [];
            foreach ($orderIds as $k => $orderId) {
                $taskOrders[] = [
                    'task_id' => $task_id,
                    'order_id' => $orderId,
                    'create_time' => date("Y-m-d H:i:s"),
                    'update_time' => date("Y-m-d H:i:s"),
                ];
            }

            PrinterTaskOrder::insert($taskOrders);
            return retSuc([], "已提交打印任务，等待打印");
        }

        $fields = "s.title as shop_title,o.shop_id,s.open_printer_task,o.id,o.order_source,o.shop_type,o.delivery_date,o.delivery_start_time,o.delivery_end_time,o.callNo,o.buyer_remark,o.menu_id,o.status,o.uid,o.total_price,o.out_trade_no,oa.province_id,oa.city_id,oa.region_id,oa.district,oa.address,oa.phone,oa.consignee";
        $model = Order::from("order as o")
            ->join("daily_menu as dm", "dm.id", "=", "o.menu_id")
            ->join("order_address as oa", "oa.order_id", "=", "o.id")
            ->join("supplier as s", "s.id", "=", "o.shop_id")
            ->when(!empty($filter['ids']), function ($query) use ($filter) {
                return $query->whereIn('o.id', $filter['ids']);
            })
            ->when(!empty($orderIds), function ($query) use ($orderIds) {
                return $query->whereIn('o.id', $orderIds);
            })
            ->when(!empty($filter['menu_id']), function ($query) use ($filter) {
                if (is_array($filter['menu_id'])) {
                    return $query->whereIn('o.menu_id', $filter['menu_id']);
                } else {
                    return $query->where('o.menu_id', intval($filter['menu_id']));
                }
            });

        $orders = $model->get(array_filter(explode(",", $fields)))->toArray();
//        file_put_contents("/tmp/order_auto.log", var_export($orders, true) . "\n", 8);

        $data = [];
        foreach ($orders as $sk => $sv) {
            $data[$sv['province_id']][$sv['city_id']][$sv['region_id']][] = $sv;
        }

        foreach ($data as $pk => $pv) {//楼
            //菜单
            $province = LouAddress::query()->where(['id' => $pk])->value("title");
            foreach ($pv as $k1 => $v1) {//层
                $city = LouAddress::query()->where(['id' => $k1])->value("title");
            }

            foreach ($v1 as $k2 => $v2) { //科室
                $region = LouAddress::query()->where(['id' => $k2])->value("title");

                foreach ($v2 as $k3 => &$v3) { // 打印订单
                    $v3['province'] = $province;
                    $v3['city'] = $city;
                    $v3['region'] = $region;
                    $district_title = LouAddress::query()->where(['id' => $v3['district']])->value("title");
                    $v3['district_title'] = $district_title == 'NA' ? "无床位" : (is_numeric($district_title) ? ($district_title . '床') : $district_title);
                    $productList = $this->getOrderProductsById($v3['id']);

                    $productList = ass_column($productList, "product_id", true);
                    $pData = [];
                    foreach ($productList as $pk => $pv) {

                        if (!in_array($pv[0]['type'], [1, 2])) { //非规格+ 套餐
                            $pData[] = [
                                'amount' => array_sum(get_column($pv, "amount")),
                                'title' => $pv[0]['title'],
                                'type' => $pv[0]['type'],
                                'price' => $pv[0]['price'],
                                'sub' => $pv[0]['skus'] ?? null,
                            ];
                            continue;
                        }

                        foreach ($pv as $sk => $sv) {
                            $pd = [
                                'amount' => $sv['amount'],
                                'title' => $sv['title'],
                                'type' => $sv['type'],
                                'price' => $sv['price'],
//                                'sub' => $pv[0]['skus'] ?? null,
                            ];
                            $combo_title = "";
                            if ($sv['type'] == 2) { //多规格
                                foreach ($sv['skus'] as $spk => $spv) {
                                    $combo_title .= $spv['spec_item_title'];
                                }
                            } else if ($sv['type'] == 1) { // 套餐
                                $combo_title = "";
                                foreach ($sv['skus'] as $spk => $spv) {
                                    $combo_title .= $spv['spec_item_title'] . ' x' . $spv['amount'] . ' ';
                                }
                            }
                            if ($combo_title) {
                                $pd['combo_title'] = $combo_title;
                            }

                            $pData[] = $pd;
                        }
                    }

                    $v3['product_amount'] = array_sum(get_column($pData, "amount"));
                    $v3['products'] = $pData;

                    if ($v3['shop_type'] == 0) {
                        $v3['delivery_date'] = date("m月d日", strtotime($v3['delivery_date'])) . ' ' . substr($v3['delivery_start_time'], 0, 5) . '-' . substr($v3['delivery_end_time'], 0, 5);
                    } else {
                        $menu = (new DailyMenuRepository())->getPrinterMenu($v3['menu_id']);
                    }

                    (new PrinterRepository())->printOrder($v3, [
                        'menu' => $menu ?? null,
                        'is_printer_now' => count($orders) == 1 ? 1 : 0,
//                        'printer_id' => $printer_id
                        'printer_id' => $printer_id ? $printer_id : (intval($filter['printer_id'] ?? 0))
                    ], intval($task_id ?? 0));

                }
            }
        }

        if ($type == 2)
            return true;

        return retSuc([], "打印成功");
    }

    /**打印档口
     * @param array $filter
     * @param null $printer_id
     * @return mixed
     */
    public function printerStall($filter = [], $printer_id = null, $type = 0)
    {
        if ($type == 1) {
            $statStalls = (new \App\Repositories\Manage\OrderRepository())->getOrderStallStat($filter);
        } else {
            $statStalls = $this->getOrderStallStat($filter, intval($printer_id));
        }
        if (!$statStalls)
            return retFail("没有符合条件的档口数据");

        $shop = Supplier::query()->where("id", $filter['shop_id'])->first();
        if (empty($shop))
            return retFail("未找到店铺");

        try {
            $res = (new PrinterRepository())->printStallOrder($statStalls, $printer_id, $shop);
            return retSuc([], "打印成功");
        } catch (Exception $e) {
            return retFail("打印失败：" . $e->getMessage());
        }

    }

    /**
     * @param array $orderIds
     * @param int $status
     * @param null $uid
     * @param int $origial 1:管理员 2：会员
     */
    public function addLog($orderIds = [], $status = 0, $uid = null, $origial = 1)
    {
        if (empty($orderIds) || $status == 0 || !$uid)
            return;

        $logs = [];
        foreach ($orderIds as $orderId) {
            $logs[] = [
                'order_id' => $orderId,
                'create_user_id' => $uid,
                'create_time' => date("Y-m-d H:i:s"),
                'update_time' => date("Y-m-d H:i:s"),
                'status' => $status,
                'original' => $origial
            ];
        }

        OrderLog::insert($logs);
        return true;
    }

    /**
     * 打印科室
     * @param array $filter
     * @param null $printer_id
     * @param int $type
     */
    public function printerKs($filter = [], $printer_id = null, $type = 0)
    {

        $orderList = $this->_get_list($filter, null, 3)
            ->join("order_address as oa", "oa.order_id", "=", "o.id")
            ->join("lou_address as l", "l.id", "=", "oa.province_id")
            ->join("lou_address as la", "la.id", "=", "oa.city_id")
            ->get(array_filter(explode(",", "o.id,s.title as shop_title,o.order_source,o.status,o.uid,oa.province_id,o.menu_id,oa.city_id,oa.region_id,oa.district,oa.address,l.title as province_title,la.title as city_title")))
            ->toArray();

        if (empty($orderList))
            return retFail("暂无订单");

        $orderList = ass_column($orderList, "menu_id", true);
        $printer_data = [];

        foreach ($orderList as $menu_id => $orders) {
            $data = [];
            $menu = (new DailyMenuRepository())->getOne($menu_id);
            foreach ($orders as $sk => $sv) {
                $data[$sv['province_id']][$sv['city_id']][$sv['region_id']][] = $sv;
            }

            foreach ($data as $k => $v) {
                $province = LouAddress::query()->where(['id' => $k])->value("title");
                $province = is_numeric($province) ? ($province . '号楼') : $province;

                foreach ($v as $k1 => $v1) {
                    $city = LouAddress::query()->where(['id' => $k1])->value("title");
                    $city = is_numeric($city) ? ($city . 'F') : $city;

                    foreach ($v1 as $k2 => $v2) {
                        $d = [];
                        $d['city'] = $city;
                        $d['province'] = $province;
                        $d['order_amount'] = count($v2);
                        $d['region'] = LouAddress::query()->where(['id' => $k2])->value("title");
                        $d['order_amount'] = count($v2);
                        if (in_array(1, get_column($v2, 'order_source'))) {
                            $d['unpaid'] = 1;
                        }

                        $productList = OrderProduct::query()
                            ->whereIn("order_id", get_column($v2, "id"))
                            ->get(["id", "type", "product_id", "amount", "order_id", "product_title as title", "product_price as price"])
                            ->toArray();

                        $productList = ass_column($productList, "product_id", true);
                        $pData = [];
                        foreach ($productList as $pk => $pv) {
                            $pd = [
                                'amount' => array_sum(get_column($pv, "amount")),
                                'title' => $pv[0]['title'],
                                'type' => $pv[0]['type'],
                                'price' => $pv[0]['price'],
//                                'sub' => $pv[0]['skus'] ?? null,
                            ];

                            $combo_title = "";
                            if ($pv[0]['type'] == 2) { //多规格
                                $skus = OrderSku::query()->where([
                                    'order_id' => $pv[0]['order_id'],
                                    'type' => 0,
                                    'goods_id' => $pk,
                                ])->orderBy("id", "asc")
                                    ->get(['id', 'spec_item_id', 'spec_item_title', 'spec_price'])
                                    ->toArray();

                                if ($skus) {
                                    $pd['skuTxt'] = implode("、", get_column($skus, "spec_item_title"));
                                    foreach ($skus as $sk => &$sv) {
                                        $sv['spec_price'] = formatNum($sv['spec_price']);
                                    }
                                }

                                $pd['sub'] = $skus;
                                foreach ($pd['sub'] as $spk => $spv) {
                                    $combo_title .= $spv['spec_item_title'];
                                }

                            } else if ($pv[0]['type'] == 1) { // 套餐

                                $pd['sub'] = OrderSku::query()->where([
                                    'order_id' => $pv[0]['order_id'],
                                    'goods_id' => $pk,
                                    'type' => 1,
                                ])->orderBy("id", "asc")
                                    ->get(['id', 'goods_id', 'spec_id', 'spec_item_id', 'spec_item_title', 'sequence', 'amount'])
                                    ->toArray();
                                if ($pd['skus']) {
                                    $pd['skuTxt'] = implode("、", get_column($pd['skus'], "spec_item_title"));
                                }

                                $combo_title = "";
                                foreach ($pd['sub'] as $spk => $spv) {
                                    $combo_title .= $spv['spec_item_title'] . ' x' . $spv['amount'] . ' ';
                                }
                            }
                            if ($combo_title) {
                                $pd['combo_title'] = $combo_title;
                            }
                            $pData[] = $pd;
                        }

                        $d['product_amount'] = array_sum(get_column($pData, "amount"));
                        $d['products'] = $pData;
                        $d['menu_id'] = $menu_id;
                        $d['printer_id'] = $printer_id;
                        $d['menu_title'] = date("m月d日", strtotime($menu['date'])) . ' ' . menu_type($menu['type']);
                        $d['shop_title'] = Supplier::query()->where(['id' => $menu['shop_id']])->value("title");
                        $printer_data[] = $d;

                        /*(new PrinterRepository())->printerKs($d, [
                            'menu' => $menu,
                            'shop_title' => Supplier::query()->where(['id' => $menu['shop_id']])->value("title"),
                            'printer_id' => $printer_id
                        ]);*/
                    }
                }
            }
        }


        if (empty($printer_data))
            return retFail("暂无需要打印的科室");

        foreach ($printer_data as $k => $v) {
            (new PrinterRepository())->printerKs($v, [
                'menu_title' => $v['menu_title'],
                'shop_title' => $v['shop_title'],
                'printer_id' => $printer_id
            ]);
        }

        return retSuc("正在打印");
    }

    /**
     * 发送提醒配送员短信
     * 待出餐
     */
    public function sendSmsToDeliver()
    {
        $cache_key = "send_sms_to_deliver";
        $send_time = Cache::get($cache_key);
        if ($send_time > strtotime("-10 minutes")) {
            return false;
        }

        $shopIds = Order::query()->distinct("shop_id")->where([
            "status" => 10,
            "delivery_status" => 10,
        ])->pluck("shop_id")->toArray();

        if (empty($shopIds) || count($shopIds) == 0)
            return;

        $shops = Supplier::query()->whereIn("id", $shopIds)
            ->whereNotNull("delivery_phone")
            ->get(["title", "delivery_phone"])
            ->toArray();

        foreach ($shops as $k => $shop) {
            if (SmsLog::query()->where(['shop_id' => $shop['id'], 'mobile' => $shop['delivery_phone']])->where("created_at", ">", date("Y-m-d H:i:s", strtotime("-10 minutes")))->count("id")) {
                continue;
            }
            $res = (new SendSmsService())->send($shop['delivery_phone'], [
                'name' => "配送员",
                'store' => $shop['title'] ?? " ",
            ]);

            if (empty($res)) continue;

            SmsLog::create([
                "shop_id" => $shop['id'],
                "mobile" => $shop['delivery_phone'],
                "code" => $res['code'],
                "message" => $res['message'],
            ]);
        }
        Cache::get($cache_key);

        return true;
    }
}